/**
 *
 */
package com.honeybees.framework.datatables.util;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;

import javax.servlet.http.HttpServletRequest;

import com.honeybees.framework.pagination.PageCalcUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.honeybees.framework.datatables.ajax.Column;
import com.honeybees.framework.datatables.ajax.DatatablesRequest;
import com.honeybees.framework.datatables.ajax.Order;
import com.honeybees.framework.datatables.ajax.Search;

/**
 * <dl>
 * <dt><b> 从 HttpServletRequest 中获取数据，构建 DatatablesRequest 对象 </b></dt>
 * <p>
 * <dd></dd>
 * </dl>
 * <p>
 * Copyright (C) All rights reserved.
 * </p>
 *
 * @author 李远明
 * @since 2017-04-08 17:41:27
 */
public final class DatatablesUtils {

    private static final Logger logger = LoggerFactory.getLogger(DatatablesRequest.class);

    /**
     * <dl>
     * <dt><b> Map all request parameters into a wrapper POJO </b></dt>
     * <p>
     * <dd>https://github.com/dandelion/dandelion-datatables.git</dd>
     * <dd>https://github.com/dandelion/dandelion-datatables-samples.git</dd>
     * <dd>https://www.datatables.net/examples/api/regex.html</dd>
     * </dl>
     *
     * @param request The request sent by Datatables containing all parameters.
     * @return a wrapper POJO.
     * @author 李远明
     * @version 2017-04-07 17:32:59
     */
    // 类内方法定义顺序依次是：公有方法或保护方法 > 私有方法 > getter/setter 方法。
    public static DatatablesRequest getFromRequest(HttpServletRequest request) {
        // Validate.notNull(request, "The HTTP request cannot be null");

        int draw = safeToInt(request.getParameter("draw"));
        int start = safeToInt(request.getParameter("start"));
        int length = safeToInt(request.getParameter("length"));

        String paramSearchVal = request.getParameter("search[value]");
        String paramSearchReg = request.getParameter("search[regex]");
        Search globalSearch = new Search(paramSearchVal, safeToBool(paramSearchReg));

        // Column definitions
        int count1 = getColumnCount(request);
        logger.trace("Number of columns: {}", count1);

        List<Column> columns = new ArrayList<>(count1);
        for (int i = 0; i < count1; i++) {
            Column col = new Column();

            col.setData(request.getParameter("columns[" + i + "][data]"));
            col.setName(request.getParameter("columns[" + i + "][name]"));
            col.setSearchable(safeToBool(request.getParameter("columns[" + i + "][searchable]")));
            col.setOrderable(safeToBool(request.getParameter("columns[" + i + "][orderable]")));

            Search colSearch = new Search();
            String searchVal = request.getParameter("columns[" + i + "][search][value]");
            String searchReg = request.getParameter("columns[" + i + "][search][regex]");
            colSearch.setValue(searchVal);
            colSearch.setRegex(safeToBool(searchReg));
            col.setSearch(colSearch);

            columns.add(col);
        }

        // Order column definitions
        int count2 = getOrderCount(request);

        List<Order> orders = new ArrayList<>(count2);
        for (int j = 0; j < count2; j++) {
            Order order = new Order();
            int column = safeToInt(request.getParameter("order[" + j + "][column]")); // columns.get(column);
            String direction = request.getParameter("order[" + j + "][dir]");
            order.setColumn(column);
            order.setDir(direction);

            orders.add(order);
        }

        DatatablesRequest ret = new DatatablesRequest(draw, start, length, globalSearch, columns, orders);

        int pageNo = PageCalcUtils.calcPageNo(start, length);
        ret.setPageNo(pageNo); // XXX 添加支持使用 pageNo 与 pageSize 的分页方式 2017-04-11 10:22:05
        ret.setPageSize(length);

        String timestamp = request.getParameter("_");
        ret.setTimestamp(safeToLong(timestamp));
        return ret;
    }

    /**
     * <dl>
     * <dt><b> 获取表格列数 </b></dt>
     * <p>
     * <dd>功能描述</dd>
     * </dl>
     *
     * @param request 当前请求
     * @return 列数
     * @author 李远明
     * @version 2017-04-07 17:33:39
     */
    private static int getColumnCount(HttpServletRequest request) {
        int count = 0;
        for (Enumeration<String> e = request.getParameterNames(); e.hasMoreElements(); ) {
            String param = e.nextElement();
            Matcher matcher = DatatablesRequest.PATTERN_columns.matcher(param);
            while (matcher.find()) {
                // Integer col = Integer.parseInt(matcher.group(1));
                int col = safeToInt(matcher.group(1));
                if (col > count) {
                    count = col;
                }
            }
        }
        if (count != 0) {
            count++;
        }
        return count;
    }

    /**
     * 获取排序列数
     *
     * @param request 当前请求
     * @return 排序列数
     */
    private static int getOrderCount(HttpServletRequest request) {
        int count = 0;
        String orderIdx = request.getParameter("order[0][column]");
        String orderDir = request.getParameter("order[0][dir]");
        if (orderIdx != null && orderDir != null) {
            count = 1;
        }
        return count;
    }

    private static int safeToInt(Object str) {
        String ss = String.valueOf(str);
        int val = 0;
        try {
            val = Integer.parseInt(ss);
        } catch (NumberFormatException e) {
            val = 0;
        }
        return val;
    }

    private static boolean safeToBool(Object str) {
        String ss = String.valueOf(str);
        boolean val = false;
        try {
            val = Boolean.parseBoolean(ss);
        } catch (NumberFormatException e) {
            val = false;
        }
        return val;
    }

    /**
     * @version 2017-04-08 11:05
     */
    private static long safeToLong(Object str) {
        String ss = String.valueOf(str);
        long val = 0;
        try {
            val = Long.parseLong(ss);
        } catch (NumberFormatException e) {
            val = 0;
        }
        return val;
    }

    /**
     * 将 DatatablesRequest 中包含的列数据转换为对象
     *
     * @param clazz 返回对象的类型
     * @return 返回的对象
     * @version 2017-04-08 00:36
     * @see #getFromRequest(HttpServletRequest)
     */
    public static <T> T getObject(DatatablesRequest datatables, Class<T> clazz) {
        // if (this.columns == null || this.columns.isEmpty()) {
        // return (T) new Object();
        // }

        List<Column> columns = datatables.getColumns(); // 2017-04-08 17:46:01

        // XXX this.columns 不会为 null 2017-04-08 10:47:23
        JSONObject jsonObject = new JSONObject(columns.size());
        for (Column column : columns) {
            String data = column.getData();
            if (!StringUtils.isBlank(data)) {
                Search search = column.getSearch();
                String value = search.getValue();
                jsonObject.put(data, value);
            }
        }
        T object = JSON.toJavaObject(jsonObject, clazz);
        return (T) object;
    }

}
